package com.yami.shop.mystery.common.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yami.shop.bean.enums.EsOperationType;
import com.yami.shop.bean.enums.ProdStatusEnums;
import com.yami.shop.bean.enums.ProdType;
import com.yami.shop.bean.enums.StationEnum;
import com.yami.shop.bean.event.EsMysteryBoxStockUpdateEvent;
import com.yami.shop.bean.event.EsMysteryBoxUpdateEvent;
import com.yami.shop.bean.model.BusinessNft;
import com.yami.shop.bean.model.Product;
import com.yami.shop.bean.model.SkuStock;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.util.OssMultipartFile;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.common.util.RedisUtil;
import com.yami.shop.dao.BusinessNftMapper;
import com.yami.shop.mystery.common.dao.MysteryBoxMapper;
import com.yami.shop.mystery.common.dao.MysteryBoxOpenRecordMapper;
import com.yami.shop.mystery.common.dao.MysteryBoxSkuMapper;
import com.yami.shop.mystery.common.dao.MysteryBoxUserArkMapper;
import com.yami.shop.mystery.common.dto.MysteryBoxExpandDto;
import com.yami.shop.mystery.common.dto.MysteryBoxOpenRecordDto;
import com.yami.shop.mystery.common.model.*;
import com.yami.shop.mystery.common.service.MysteryBoxExtensionService;
import com.yami.shop.mystery.common.service.MysteryBoxService;
import com.yami.shop.service.*;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author wxf
 * @date 2023/4/6 10:47
 */
@Service
@AllArgsConstructor
public class MysteryBoxServiceImpl extends ServiceImpl<MysteryBoxMapper, MysteryBox> implements MysteryBoxService {

    private static final String REDISSON_LOCK_PREFIX = "redisson_lock:";

    private final RedissonClient redissonClient;

    private final MysteryBoxMapper mysteryBoxMapper;

    private final MysteryBoxExtensionService extensionService;

    private final ProductService productService;

    private final MysteryBoxSkuMapper mysteryBoxSkuMapper;

    private final SkuStockService skuStockService;

    private final ApplicationEventPublisher eventPublisher;

    private final CategoryService categoryService;

    private final MysteryBoxOpenRecordMapper mysteryBoxOpenRecordMapper;

    private final BusinessNftMapper businessNftMapper;

    private final MysteryBoxUserArkMapper mysteryBoxUserArkMapper;

    private final SysConfigService sysConfigService;

    private final AttachFileService attachFileService;

    @Override
    public IPage<MysteryBox> getPage(PageParam<MysteryBox> page, MysteryBox param) {
        IPage<MysteryBox> pageVO = mysteryBoxMapper.getPage(page, param);
        return pageVO;
    }

    @Override
    public IPage<MysteryBox> getPlatformMysteryBoxPage(PageParam<MysteryBox> page, MysteryBox param) {
        IPage<MysteryBox> platformMysteryBoxPage = mysteryBoxMapper.getPlatformMysteryBoxPage(page, param);
        return platformMysteryBoxPage;
    }

    @Override
    public IPage<MysteryBox> getMyBoxPage(PageParam<MysteryBox> page, String userId, MysteryBox param) {
        // 获取所有盲盒列表
        IPage<MysteryBox> list = mysteryBoxMapper.getMyBoxPage(page, userId, param);
        // 判断状态
        for (MysteryBox mysteryBox : list.getRecords()) {
            // 如果没有未开的盒子状态为 2 --- 已开启
            if (mysteryBox.getBoxCount() == 0) {
                mysteryBox.setOpenStatus(2);
                // 获取所有开启记录
                QueryWrapper<MysteryBoxOpenRecord> mysteryBoxOpenRecordQueryWrapper = new QueryWrapper<>();
                mysteryBoxOpenRecordQueryWrapper.eq("uid", userId);
                mysteryBoxOpenRecordQueryWrapper.eq("bid", mysteryBox.getId());
                Long allRecord = mysteryBoxOpenRecordMapper.selectCount(mysteryBoxOpenRecordQueryWrapper);
                mysteryBox.setMyHold(allRecord.intValue());
                continue;
            }
            // 如果有未开的盒子 并且 有开盒记录 状态为 1 --- 部分开启
            QueryWrapper<MysteryBoxOpenRecord> mysteryBoxOpenRecordQueryWrapper = new QueryWrapper<>();
            mysteryBoxOpenRecordQueryWrapper.eq("uid", userId);
            mysteryBoxOpenRecordQueryWrapper.eq("bid", mysteryBox.getId());
            mysteryBoxOpenRecordQueryWrapper.ne("status", 0);
            Long aLong = mysteryBoxOpenRecordMapper.selectCount(mysteryBoxOpenRecordQueryWrapper);
            if (aLong > 0) {
                mysteryBox.setOpenStatus(1);
                mysteryBox.setMyHold(mysteryBox.getMyHold() + aLong.intValue());
                continue;
            }
            // 如果有未开的盒子 并且 没有有开盒记录 状态为 0 --- 未开启
            mysteryBox.setOpenStatus(0);
        }
        // 通过状态排序 升序
        List<MysteryBox> collect = list.getRecords().stream().sorted(Comparator.comparing(MysteryBox::getOpenStatus)).collect(Collectors.toList());
        list.setRecords(collect);
        return list;
    }

    @Override
    public Long getMyBoxNum(String userId, String channelCode) {
        Long boxNum = mysteryBoxMapper.getMyBoxNum(userId, channelCode);
        return boxNum == null ? 0L : boxNum;
    }

    @Override
    public void saveMysteryBox(MysteryBox param) {

        if (Objects.isNull(param.getStatus())) {
            param.setStatus(ProdStatusEnums.NORMAL.getValue());
        }
        param.setCreateTime(new Date());
        param.setActivityId(0L);
        // 1、校验商品信息
        List<MysteryBoxExtension> prods = param.getProds();
        List<Long> prodIds = prods.stream().map(p -> p.getPid().longValue()).collect(Collectors.toList());
        long prodCount = productService.count(new LambdaQueryWrapper<Product>()
                .eq(Product::getShopId, param.getShopId()).eq(Product::getSource, 0).eq(Product::getMold, 2)
                .eq(Product::getProdType, ProdType.PROD_TYPE_NORMAL)
                .in(Product::getProdId, prodIds));
        if (prodCount != prods.size()) {
            // 商品无法参与盲盒活动
            throw new YamiShopBindException("商品无法参与盲盒活动");
        }

        // 2、校验商品库存信息
        BigDecimal probability = BigDecimal.ZERO; // 开盲盒概率
        if (param.getIsLosingLottery() == 1 && param.getLosingLottery() != null) {
            probability = new BigDecimal(Double.toString(param.getLosingLottery()));
        }
        // 2.1校验盲盒概率
        for (MysteryBoxExtension prod : prods) {
            probability = probability.add(new BigDecimal(Double.toString(prod.getRealProbability())));
        }
        if (100 != probability.intValue()) {
            // 商品无法参与盲盒活动
            throw new YamiShopBindException("盲盒商品实际概率和空奖概率总和不为100%");
        }
        if (param.getIsLosingLottery() == 1) {
            MysteryBoxExtension mysteryBoxExtension = new MysteryBoxExtension();
            mysteryBoxExtension.setPid(-1L);
            mysteryBoxExtension.setRealProbability(param.getLosingLottery());
            mysteryBoxExtension.setShowProbability(param.getLosingLottery());
            mysteryBoxExtension.setHits(0);
            mysteryBoxExtension.setLevel(1);
            mysteryBoxExtension.setStocks(param.getLosingLotteryStock().intValue());
            mysteryBoxExtension.setTotalStocks(param.getLosingLotteryStock().intValue());
            prods.add(mysteryBoxExtension);
        }
        param.setUpdateTime(new Date());
        param.setPutawayTime(new Date());
        //2.2 保存盲盒盒子
        this.saveMysteryBox(param, prods);
    }

    @Override
    public void updateMysteryBox(MysteryBox param) {
        mysteryBoxMapper.updateById(param);
        eventPublisher.publishEvent(new EsMysteryBoxUpdateEvent(param.getId(), null, EsOperationType.UPDATE));
    }

    @Override
    public void deleteMysteryBox(Long id) {
        MysteryBox box = this.getById(id);
        Integer oldStatus = box.getStatus();
        if (!Objects.equals(StationEnum.INVALID.getValue(), oldStatus)) {
            // 秒杀活动未关闭，无法删除
            throw new YamiShopBindException("盲盒盒子未关闭，无法删除");
        }
        box.setIsDelete(1);
        box.setStatus(oldStatus);
        this.updateById(box);
        eventPublisher.publishEvent(new EsMysteryBoxUpdateEvent(id, null, EsOperationType.DELETE));
    }

    @Override
    public MysteryBox detail(Long id) {
        MysteryBox detail = getById(id);
        if (null == detail) {
            return null;
        }
        List<MysteryBoxExtension> list = extensionService.list(new LambdaQueryWrapper<MysteryBoxExtension>().eq(MysteryBoxExtension::getBid, id));
        List<MysteryBoxExtension> mysteryBoxProds = new ArrayList<>();
        for (MysteryBoxExtension boxExtension : list) {
            if (boxExtension.getPid() == -1) {
                continue;
            }
            MysteryBoxExtension mysteryBoxProd = BeanUtil.copyProperties(boxExtension, MysteryBoxExtension.class);
            Product product = productService.getProductById(mysteryBoxProd.getPid().longValue());
            if (ObjectUtil.isNotEmpty(product)) {
                mysteryBoxProd.setPic(product.getPic());
                mysteryBoxProd.setProdName(product.getProdName());
            }
            mysteryBoxProds.add(mysteryBoxProd);
        }
        detail.setProds(mysteryBoxProds);
        MysteryBoxSku boxSku = mysteryBoxSkuMapper.getByMysteryBoxId(id);
        detail.setBoxSku(boxSku);

        // 平台分类、店铺分类信息
        detail.setCategoryVO(categoryService.getInfo(detail.getCategoryId()));
        if (Objects.nonNull(detail.getShopCategoryId()) && !Objects.equals(detail.getShopCategoryId(), Constant.PLATFORM_SHOP_ID)) {
            detail.setShopCategoryVO(categoryService.getInfo(detail.getShopCategoryId()));
        }

        return detail;
    }

    @Override
    public void mysteryBoxStatus(Long id, Integer status) {

        MysteryBox box = this.getById(id);
        // 判断盲盒当前是否参加活动，如果是不能修改
        if (box.getProdType() != 0 && Objects.equals(StationEnum.INVALID.getValue(), status)) {
            throw new YamiShopBindException("盲盒盒子正在参加活动，不能被下架");
        }
        box.setStatus(status);
        this.updateById(box);
        eventPublisher.publishEvent(new EsMysteryBoxUpdateEvent(id, null, EsOperationType.UPDATE));
    }

    @Override
    public List<MysteryBoxExpandDto> getBoxProdsByPid(Long bid) {
        List<MysteryBoxExpandDto> retList = new ArrayList<>();
        // 获取盲盒管理商品
        List<MysteryBoxExtension> boxProds = extensionService.list(new LambdaQueryWrapper<MysteryBoxExtension>().eq(MysteryBoxExtension::getBid, bid));
        // 获取盲盒内商品信息
        for (MysteryBoxExtension boxProd : boxProds) {
            MysteryBoxExpandDto blindboxExpandVO = new MysteryBoxExpandDto();
            BeanUtil.copyProperties(boxProd, blindboxExpandVO);
            BigDecimal brod = new BigDecimal(boxProd.getRealProbability().toString()).divide(new BigDecimal("100"));
            blindboxExpandVO.setProb(brod.doubleValue());
            if (boxProd.getPid() != -1) {
                Product product = productService.getProductById(boxProd.getPid().longValue());
                blindboxExpandVO.setName(product.getProdName());
                //blindboxExpandVO.setDawDenomId(product.getVirtualProductForm().getDenomId());
                blindboxExpandVO.setDawNum(boxProd.getStocks());
                blindboxExpandVO.setStock(boxProd.getStocks());
                blindboxExpandVO.setMainImg(product.getPic());
                retList.add(blindboxExpandVO);
            } else {
                blindboxExpandVO.setDawNum(boxProd.getStocks());
                retList.add(blindboxExpandVO);
            }
        }
        return retList;
    }

    @Override
    public List<MysteryBox> getListData(Long shopId) {
        List<MysteryBox> list = this.list(new LambdaQueryWrapper<MysteryBox>().eq(MysteryBox::getShopId, shopId).eq(MysteryBox::getStatus, 0).eq(MysteryBox::getProdType, 0).eq(MysteryBox::getIsDelete, 0));
        return list;
    }

    @Override
    public List<MysteryBox> getListByShopIdAndStatus(Long shopId, Integer status) {
        List<MysteryBox> hasStockBoxList = mysteryBoxMapper.getHasStockBoxList(shopId, status);
        return hasStockBoxList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void invalidById(MysteryBox mysteryBox) {
        this.updateById(mysteryBox);
        eventPublisher.publishEvent(new EsMysteryBoxUpdateEvent(mysteryBox.getId(), null, EsOperationType.UPDATE));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveMysteryBox(MysteryBox mysteryBox, List<MysteryBoxExtension> mysteryBoxExtensions) {

        Map<Long, SkuStock> skuStockMap = new HashMap<>();
        for (MysteryBoxExtension prod : mysteryBoxExtensions) {
            if (prod.getPid() == -1) {
                continue;
            }
            prod.setTotalStocks(prod.getStocks());
            List<SkuStock> skuList = skuStockService.listSkuStockByProdId(prod.getPid());
            if (CollectionUtils.isEmpty(skuList) || skuList.size() != 1 || skuList.get(0).getStocks() < prod.getTotalStocks()) {
                // 商品库存不足，不能参加盲盒活动
                throw new YamiShopBindException("商品库存不足，不能参加盲盒活动");
            }
            skuStockMap.put(prod.getPid(), skuList.get(0));
        }
        mysteryBox.setStatus(0);
        mysteryBox.setIsDelete(0);

        // 保存盲盒盒子信息
        mysteryBoxMapper.insert(mysteryBox);

        // 创建二维码 -- 商品详情
        createQrcode(mysteryBox.getId(), mysteryBox.getShopId());

        mysteryBoxExtensions.forEach(box -> box.setBid(mysteryBox.getId()));

        List<SkuStock> lockStockList = new ArrayList<>();
        for (MysteryBoxExtension box : mysteryBoxExtensions) {
            if (box.getPid() == -1) {
                continue;
            }
            SkuStock stock = skuStockMap.get(box.getPid());
            stock.setLockStock(box.getStocks()); // 放入需要扣除的库存
            lockStockList.add(stock);
        }
        EsMysteryBoxStockUpdateEvent event = new EsMysteryBoxStockUpdateEvent(mysteryBox.getId(), lockStockList, EsOperationType.UPDATE_BATCH, null);
        eventPublisher.publishEvent(event);
        if (StringUtils.isNotBlank(event.getReuslt())) {
            // 商品库存不足，不能参加盲盒活动
            throw new YamiShopBindException(event.getReuslt());
        }
        // 保存盲盒商品sku信息
        extensionService.saveBatch(mysteryBoxExtensions);

        // 保存盲盒盒子sku信息
        MysteryBoxSku boxSku = new MysteryBoxSku();
        boxSku.setMysteryBoxId(mysteryBox.getId());
        boxSku.setActualStock(mysteryBox.getTotalStocks().intValue());
        boxSku.setLockStock(0);
        boxSku.setStocks(mysteryBox.getTotalStocks().intValue());
        mysteryBoxSkuMapper.insert(boxSku);
        eventPublisher.publishEvent(new EsMysteryBoxUpdateEvent(mysteryBox.getId(), null, EsOperationType.SAVE));
    }

    @Override
    public Boolean decrMysteryBoxSkuStocks(Long boxId, Integer prodCount) {

        // 这里一进来就减库存，但是为了防止少卖，120秒会自己更新库存~因为缓存只有60秒
        boolean removeStockCache = checkMysteryBoxSkuStocks(boxId, prodCount);
        // 更新秒杀sku库存，乐观锁
        boolean removeSkuStock = mysteryBoxSkuMapper.updateStocks(boxId, prodCount) >= 1;
        // 数据不一致删除 缓存 重新加载 最新的库存数据
        if(removeSkuStock != removeStockCache){
            // 清除库存的缓存
            RedisUtil.del(Constant.MYSTERY_BOX_SKU_STOCKS_PREFIX + boxId);
        }

        return removeStockCache && removeSkuStock;
    }

    @Override
    public List<MysteryBox> selectDelist() {
        return mysteryBoxMapper.selectDelist();
    }

    @Override
    public MysteryBox myBoxDetail(String userId, Long boxId) {
        // 获取盲盒信息
        MysteryBox box = mysteryBoxMapper.myBoxDetail(userId, boxId);
        box.setMyHold(box.getMyHold() + box.getMyOpenNum());
        return box;
    }

    @Override
    public IPage<MysteryBoxOpenRecordDto> getBoxrecords(PageParam<MysteryBoxOpenRecord> page, String userId, Long boxId) {
        // 获取盲盒记录信息
        PageParam<MysteryBoxOpenRecordDto> mysteryBoxOpenRecordPage = mysteryBoxOpenRecordMapper.selectPageByUserIdAnBoxId(page, boxId, userId);
        mysteryBoxOpenRecordPage.getRecords().forEach(s -> {
            // 2 为 资产已到账 查询商品信息
            if (s.getStatus() != 0) {
                Product productInfo = productService.getProductInfo(s.getPid());
                s.setProdName(productInfo.getProdName());
                s.setPic(productInfo.getPic());
            }
        });
        return mysteryBoxOpenRecordPage;
    }

    @Override
    public List<MysteryBoxOpenRecord> openMyBox(String userId, Long boxId, Integer openNum) {

        List<MysteryBoxOpenRecord> list = mysteryBoxOpenRecordMapper.selectList(Wrappers.lambdaQuery(MysteryBoxOpenRecord.class)
                .eq(MysteryBoxOpenRecord::getBid, boxId).eq(MysteryBoxOpenRecord::getUid, userId).eq(MysteryBoxOpenRecord::getStatus, 0).last("limit " + openNum));
        if (list.size() < openNum) {
            throw new YamiShopBindException("可开启数量不足");
        }
        for (MysteryBoxOpenRecord record : list) {
            record.setOpenTime(new Date());
            if (record.getPid() == -1) {
                record.setStatus(2);
                mysteryBoxOpenRecordMapper.updateById(record);
                continue;
            }

            record.setStatus(1);
            mysteryBoxOpenRecordMapper.updateById(record);
            Product product = productService.getById(record.getPid());
            BusinessNft nft = new BusinessNft();
            nft.setBusinessType(1);
            nft.setProdId(String.valueOf(record.getPid()));
            nft.setProdName(product.getProdName());
            nft.setUserId(record.getUid());
            nft.setNum(1);
            nft.setStatus(0);
            nft.setOutId(record.getId().toString());
            businessNftMapper.insert(nft);
            record.setPic(product.getPic());
            record.setProdName(product.getProdName());
        }

        // 减少用户开盒次数
        MysteryBoxUserArk mysteryBoxUserArk = mysteryBoxUserArkMapper.selectOne(new LambdaQueryWrapper<MysteryBoxUserArk>().eq(MysteryBoxUserArk::getUid, userId).eq(MysteryBoxUserArk::getBid, boxId));
        mysteryBoxUserArk.setCount(mysteryBoxUserArk.getCount() - openNum);
        mysteryBoxUserArkMapper.updateById(mysteryBoxUserArk);

        return list;
    }

    @Override
    public IPage<MysteryBoxOpenRecord> getMyOpenBoxPage(PageParam<MysteryBoxOpenRecord> page, String userId, MysteryBoxOpenRecord param) {
        return mysteryBoxOpenRecordMapper.getMyOpenBoxPage(page, userId, param);
    }

    @Override
    public void createQrcode(Long boxId, Long shopId) {
        QrConfig config = new QrConfig(300, 300);
        // 获取微发行链接地址
        String url = sysConfigService.getValue("V_URL") + "/#/?shopId=" + shopId + "&prodId=" + boxId + "&type=1";
        BufferedImage qrgenerate = QrCodeUtil.generate(url, config);
        //保存图片
        ByteArrayOutputStream qrOutputStream = new ByteArrayOutputStream();
        //读文件
        try {
            ImageIO.write(qrgenerate, "jpg", qrOutputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        MultipartFile ossMultipartFile = new OssMultipartFile("111.jpg", ".jpg", qrOutputStream.toByteArray());
        try {
            String fileName = attachFileService.uploadFile(ossMultipartFile.getBytes(), UUID.fastUUID() + ".jpg");
            // 保存链接信息
            UpdateWrapper<MysteryBox> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id", boxId);
            updateWrapper.set("link_addr", url);
            updateWrapper.set("qrcode_addr", fileName);
            this.update(updateWrapper);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 校验当前时间库存是否够用
     *
     * @param mysteryBoxId
     * @param prodCount
     * @return
     */
    private boolean checkMysteryBoxSkuStocks(Long mysteryBoxId, Integer prodCount) {

        String key = Constant.MYSTERY_BOX_SKU_STOCKS_PREFIX + mysteryBoxId;

        Long cacheStocks = RedisUtil.getLongValue(key);

        if (cacheStocks != null && cacheStocks <= 0) {
            // 库存不足
            return false;
        }
        // 如果没有库存就缓存一个库存
        RLock rLock = redissonClient.getLock(REDISSON_LOCK_PREFIX + ":getMysteryBoxSkuStocks");
        try {
            // 加锁，防止缓存击穿
            int lockWait = 10;
            if (cacheStocks == null || RedisUtil.getExpire(key) < 1) {
                if (rLock.tryLock(lockWait, lockWait, TimeUnit.SECONDS)) {
                    // 再获取一遍缓存
                    cacheStocks = RedisUtil.getLongValue(key);
                    if (cacheStocks == null) {
                        Integer mysteryBoxStocks = mysteryBoxSkuMapper.getByMysteryBoxId(mysteryBoxId).getStocks();
                        if (mysteryBoxStocks > 0) {
                            RedisUtil.setLongValue(key, Long.valueOf(mysteryBoxStocks), -1);
                        } else {
                            RedisUtil.setLongValue(key, 0L, 30);
                        }
                        cacheStocks = Long.valueOf(mysteryBoxStocks);
                    }
                } else {
                    // 网络异常
                    throw new YamiShopBindException("yami.network.exception");
                }
            }

            if (cacheStocks == null || cacheStocks < prodCount || RedisUtil.decr(key, prodCount) < 0) {
                RedisUtil.expire(key, 30);
                // 本轮商品已被秒杀完毕，还有用户未支付，还有机会哟
                return false;
            }

        } catch (InterruptedException e) {
            log.error("InterruptedException:", e);
        } finally {
            try {
                if (rLock.isLocked()) {
                    rLock.unlock();
                }
            } catch (Exception e) {
                log.error("Exception:", e);
            }
        }
        return true;

    }

}
